// Debugger for demo
$ = function(a) {
  return document.getElementById(a);
};
var tests = {
  "test-1": "test/test.xml",
  "test-2": "test/test2.xml",
  "test-3": "test/rokubunnoichi.xml",
  "test-4": "test/mikunoshoushitsu.xml",
  "test-5": "test/unowen.xml",
  "test-6": "test/comment.xml",
  "test-7": "test/extended.xml",
  "test-8": "test/boss.xml",
  "test-9": "test/utsukushiki_mono.xml",
  "test-s": "test/scripting/kanpai.xml",
  "test-ac-1": {
    "f": 'test/ACFun.json',
    "p": "acfun"
  },
  "test-ac-2": {
    "f": 'test/ac940133.json',
    "p": "acfun"
  },
  "test-ts-1": {
    "f": "test/invalid/no_closing.xml",
    "p": "bilibili-text"
  },
  "test-ts-2": {
    "f": "test/invalid/syntax_error.xml",
    "p": "bilibili-text"
  },
  "test-ts-3": {
    "f": "test/invalid/xss.xml",
    "p": "bilibili-text"
  }
};

var debugs = {
  "preset-1-run": "cm.filter.addModifier(function(cmt){if(cmt.pool === 0) return null; return cmt;})",
  "preset-2-run": "cm.filter.setRuntimeFilter(function(cmt){if(cmt.hasSet) return cmt; cmt.hasSet = true; cmt.onclick = function(){if(!this.hold){this.hold = true;this.style.border=\"1px solid #ff0\";this.style.zIndex =\"9999\"; this.style.backgroundColor=\"#000\";}else{this.hold = false;this.style.border=\"0px\";this.style.backgroundColor=\"\";}}; return cmt;});",
  "preset-3-run": "cm.filter.addModifier(function(cmt){cmt.border = true; return cmt;})",
};

var state = {
  "format": "hrf",
  "cw": "p-main",
  "mode": "timer",
};

var windowbinds = {
  "p-main": {
    "id": "w-main",
    "opacityOnly": true
  },
  "p-code": {
    "id": "w-code"
  },
  "p-help": {
    "id": "w-help"
  }
};

var CCLDBG = new function() {
  var x = 0;
  var profiles = [];
  var pmax = 0;
  var smax = 0;
  var sample = 0;
  var avg = 0;
  this.reset = function() {
    profiles = [];
    x = 0;
    pmax = 0;
    avg = 0;
    sample = 0;
  };
  this.profiler = function() {
    var t = (new Date()).getTime();
    var tdiff = t - x;
    if (tdiff < 10) {
      return;
    }
    sample++;
    if (sample % 100 == 0) {
      sample = 0;
      profiles.push(-1);
    }
    if (tdiff < 5000) {
      avg += tdiff / 300;
      profiles.push(tdiff);
      if (tdiff > pmax) {
        pmax = tdiff;
      }
      if (tdiff > smax) {
        smax = tdiff;
      }
      if (profiles.length > 300) {
        var del = profiles.shift();
        avg -= del / 300;
      }
    }
    x = t;
  };
  this.render = function() {
    if (smax > avg * 4) {
      smax = Math.round(avg * 4)
    }
    var ctx = $("profiler").getContext("2d");
    if (ctx != null) {
      ctx.fillStyle = "#00FFFF";
      ctx.clearRect(0, 0, 300, 40);
      for (var i = 0; i < profiles.length; i++) {
        if (profiles[i] < 0) {
          ctx.fillStyle = "#FF00FF";
          ctx.fillRect(i, 0, 1, 40);
          ctx.fillStyle = "#00FFFF";
          continue;
        }
        var barh = Math.round((profiles[i] / (smax + 5)) * 40);
        if (barh <= 40) {
          ctx.fillRect(i, 40 - barh, 1, barh);
        } else {
          ctx.fillStyle = "#FFFF00";
          ctx.fillRect(i, 40 - barh, 1, barh);
          ctx.fillStyle = "#00FFFF";
        }
      }
      ctx.fillStyle = "#FF0000";
      ctx.fillRect(0, 40 - Math.round(avg / (smax + 5) * 40), 300, 1);
      ctx.fillStyle = "#00FFFF";
    };
    $("pf-stats").innerHTML = "AVG:" + Math.round(avg) + "<br>" + "MAX:" + pmax + "<br>FPS:" + (avg > 0 ? Math.round(1000 / avg) : 0);
  };
  this.getProfiles = function() {
    return profiles;
  };
  var self = this;
  var t = -1;;
  this.on = function() {
    if (t > 0)
      return;
    t = setInterval(function() {
      self.render();
    }, 150);
    $("profiler-start").style.color = "#0ff";
  };
  this.off = function() {
    if (t < 0)
      return;
    clearInterval(t);
    t = -1;
    $("profiler-start").style.color = "";
    $("pf-stats").innerHTML = "PF:OFF";
  };
  this.isOn = function() {
    return t >= 0;
  };
};

function bind() {
  window.cm = new CommentManager($('commentCanvas'));
  cm.init();

  var tmr = -1;
  var start = 0;
  var playhead = 0;

  $("control-stop").addEventListener("click", function(e) {
    if (e && e.preventDefault)
      e.preventDefault();
    stop();
  });

  $("control-resume").addEventListener("click", function(e) {
    if (e && e.preventDefault)
      e.preventDefault();
    resume();
  });

  $("control-reset").addEventListener("click", function(e) {
    if (e && e.preventDefault)
      e.preventDefault();
    playhead = 0;
    start = (new Date()).getTime();
    cm.clear();
  });

  $("w-main").addEventListener("keydown", function(k) {
    if (k) {
      if (k.keyCode === 70) {
        state.format = (state.format === "hrf" ? "std" : "hrf");
      } else if (k.keyCode === 32) {
        if (tmr < 0) {
          resume();
        } else {
          stop();
        }
      } else if (k.keyCode === 66) {
        $("player").style.backgroundColor = "#000"; //b
        $("c-region").style.color = "#fff";
      } else if (k.keyCode === 87) {
        $("player").style.backgroundColor = "#fff"; //w
        $("c-region").style.color = "#000";
      } else if (k.keyCode === 82) {
        var x = prompt("Resize player window (WxH or 'old','new')");
        if (x) {
          if (x === "new")
            x = "672x438";
          if (x === "old")
            x = "512x384";
          var wh = x.split("x");
          var w = parseInt(wh[0]);
          var h = parseInt(wh[1]);
          if (w > 0 && h > 0) {
            $("player").style.height = h + "px";
            $("player-unit").style.width = w + "px";
            if (cm)
              cm.setBounds();
          }
        }
      } else if (k.keyCode === 80) { //p
        if (CCLDBG.isOn()) {
          CCLDBG.off();
          cm.filter.setRuntimeFilter(null);
        } else {
          CCLDBG.on();
          cm.filter.setRuntimeFilter(function(cmt) {
            CCLDBG.profiler();
            return cmt;
          });
        }
      }
    }
  });

  window.isDebugRunning = function() {
    return tmr >= 0 || !$("abpVideo").paused;
  };

  window.displayTime = function(playhead) {
    requestAnimationFrame(function () {
      if (state.format === "hrf") {
        var sec = Math.floor(playhead / 1000);
        var millis = playhead % 1000;
        var millisText = (millis > 99 ? millis : ("0" + (millis > 9 ? millis : "0" + millis)));
        $("control-status").textContent = Math.floor(sec / 60) + ":" +
          ((sec % 60) > 9 ? (sec % 60) : "0" + (sec % 60)) + ":" + millisText;
      } else {
        $("control-status").textContent = playhead;
      }
    })
  };

  $("control-status").addEventListener("dblclick", function(e) {
    var x = prompt("Please input time (" + (state.format === "hrf" ? "xx:xx:xxx" : "xxx") + "):");
    if (!x || x === "")
      return;
    if (state.format === "hrf") {
      var y = x.split(":");
      var m = parseInt(y[0]);
      var s = parseInt(y[1]);
      var ml = parseInt(y[2]);
      playhead = m * 60000 + s * 1000 + ml;
    } else {
      try {
        playhead = parseInt(x);
      } catch (e) {}
    }
  });

  function stop() {
    if (state.mode === "timer") {
      cm.stop();
      $("control-status").className = "status";
      clearInterval(tmr);
      tmr = -1;
    } else {
      $("abpVideo").pause();
    }
  }

  function resume() {
    if (state.mode !== "timer") {
      $("abpVideo").play();
      return;
    }
    if (tmr !== -1)
      return;
    $("control-status").className = "status active";
    cm.start();
    start = new Date().getTime() - playhead;
    tmr = setInterval(function() {
      playhead = new Date().getTime() - start;
      displayTime(playhead);
      cm.time(playhead);
    }, 42);
  }

  /** Load **/
  window.loadDM = function(dmf, provider) {
    if (window._provider && window._provider instanceof CommentProvider) {
      window._provider.destroy();
    }
    window._provider = new CommentProvider();
    cm.clear();
    dmf = "../" + dmf;
    window._provider.addTarget(cm);
    start = 0;

    try {
      clearTimeout(tmr);
    } catch (e) {}
    if (trace) {
      trace("Loading " + dmf + " : " + provider);
    }
    switch (provider) {
      case "acfun":
        window._provider.addStaticSource(
          CommentProvider.JSONProvider('GET', dmf),
          CommentProvider.SOURCE_JSON).addParser(
          new AcfunFormat.JSONParser(),
          CommentProvider.SOURCE_JSON);
        break;
      case "cdf":
        window._provider.addStaticSource(
          CommentProvider.JSONProvider('GET', dmf),
          CommentProvider.SOURCE_JSON).addParser(
          new CommonDanmakuFormat.JSONParser(),
          CommentProvider.SOURCE_JSON);
        break;
      case "bilibili-text":
        window._provider.addStaticSource(
          CommentProvider.TextProvider('GET', dmf),
          CommentProvider.SOURCE_TEXT).addParser(
          new BilibiliFormat.TextParser(),
          CommentProvider.SOURCE_TEXT);
        break;
      case "bilibili":
      default:
        window._provider.addStaticSource(
          CommentProvider.XMLProvider('GET', dmf),
          CommentProvider.SOURCE_XML).addParser(
          new BilibiliFormat.XMLParser(),
          CommentProvider.SOURCE_XML);
        break;
    }
    window._provider.start().then(function() {
      cm.start();
      $("control-status").className = "status active";
      if (state.mode !== "timer") {
        $("abpVideo").play();
        return;
      }
      start = new Date().getTime();
      tmr = setInterval(function() {
        playhead = new Date().getTime() - start;
        cm.time(playhead);
        displayTime(playhead);
      }, 42);
    }).catch(function(e) {
      alert(e);
    });
  };

  var isWindowedFullscreen = false;

  function launchFullScreen(element) {
    cm.setBounds();
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.mozRequestFullscreen) {
      element.mozRequestFullscreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen();
    }
  }

  function launchWindowFull(element, e2) {
    if (!isWindowedFullscreen) {
      element.style.position = "fixed";
      element.style.top = "0";
      element.style.bottom = "0";
      element.style.left = "0";
      element.style.right = "0";
      element.style.width = "auto";
      element.style.height = "auto";
      e2.style.height = "100%";
    } else {
      element.style.position = "";
      element.style.top = "";
      element.style.bottom = "";
      element.style.left = "";
      element.style.right = "";
    }
    isWindowedFullscreen = !isWindowedFullscreen;
  }
  // Add Fullscreen Handlers
  var fs = function() {
    cm.setBounds();
  };
  document.addEventListener("fullscreenchange", fs);
  document.addEventListener("webkitfullscreenchange", fs);
  document.addEventListener("mozfullscreenchange", fs);

  $("fs-all").addEventListener("click", function(e) {
    if (e && e.preventDefault)
      e.preventDefault();
    launchFullScreen($("player-unit"));
  });
  $("fs-win").addEventListener("click", function(e) {
    if (e && e.preventDefault)
      e.preventDefault();
    launchWindowFull($("player-unit"), $("player"));
  });
}

function bindWindow() {
  for (var w in windowbinds) {
    $(w).addEventListener("click", function(e) {
      if (state.cw === this.id)
        return;
      if (window.isDebugRunning()) {

      }
      state.cw = this.id;
      for (var win in windowbinds) {
        $(win).className = "button";
        if ($(windowbinds[win].id) && !windowbinds[win].opacityOnly) {
          $(windowbinds[win].id).style.display = "none";
        } else if ($(windowbinds[win].id) && windowbinds[win].opacityOnly) {
          $(windowbinds[win].id).style.opacity = "0";
        }
      }
      this.className = "button active";
      try {
        $(windowbinds[this.id].id).style.display = "";
        $(windowbinds[this.id].id).style.opacity = "1";
      } catch (e) {
        console.log(e);
      }
    });
  }
};

function bindTests() {
  for (var test in tests) {
    try {
      $(test).addEventListener("click", (function() {
        var url = tests[test];
        return function() {
          if (typeof url === "string") {
            loadDM(url);
          } else {
            loadDM(url.f, url.p);
          }
        }
      })());
    } catch (e) {}
  }
  $("profiler-start").addEventListener("click", function(e) {
    CCLDBG.reset();
    CCLDBG.on();
    cm.filter.setRuntimeFilter(function(cmt) {
      CCLDBG.profiler();
      return cmt;
    });
    e.preventDefault();
  });
  $("video-demo").addEventListener("click", function(e) {
    var x = prompt("Please give video URL");
    if (!x) {
      return;
    }
    if (x == "") {
      $("abpVideo").innerHTML = '<source src="http://content.bitsontherun.com/videos/bkaovAYt-52qL9xLP.mp4" type="video/mp4">' +
        '<source src="http://content.bitsontherun.com/videos/bkaovAYt-27m5HpIu.webm" type="video/webm">';
    } else {
      $("abpVideo").innerHTML = '<source src="' + x + '">';
    }
    bindVideo($("abpVideo"), cm);
    state.mode = 'video';
    loadDM(tests['test-6']);
  });
  $("load-cmt-file").addEventListener("click", function(e) {
    var x = prompt("Please give comment file URL");
    if (!x) {
      return;
    }
    loadDM(x);
  });
}

function bindResize() {
  var sX = 0,
    sY = 0;
  var iX = 0,
    iY = 0;
  var isDownTB = false;
  var isDownLR = false;
  document.addEventListener("dblclick", function() {
    isDownTB = false;
    isDownLR = false;
  });
  $("control-resize-lr").addEventListener("mousedown", function(e) {
    sX = e.clientX;
    iX = $("player-unit").offsetWidth;
    iY = $("player").offsetHeight;
    $("commentCanvas").style.border = "1px solid #0ff";
    isDownLR = true;
    $("c-region").style.display = "";
  });
  $("control-resize-tb").addEventListener("mousedown", function(e) {
    sY = e.clientY;
    iX = $("player-unit").offsetWidth;
    iY = $("player").offsetHeight;
    $("commentCanvas").style.border = "1px solid #0ff";
    isDownTB = true;
    $("c-region").style.display = "";
  });
  document.addEventListener("mousemove", function(e) {
    if (isDownTB) {
      var yDelta = e.clientY - sY;
      $("player").style.height = (iY + yDelta) + "px";
      $("c-region").innerHTML = iX + "x" + (iY + yDelta);
    } else if (isDownLR) {
      var xDelta = e.clientX - sX;
      $("player-unit").style.width = (iX + xDelta) + "px";
      $("c-region").innerHTML = (iX + xDelta) + "x" + iY;
    }
  });
  document.addEventListener("mouseup", function(e) {
    if ((isDownTB || isDownLR)) {
      if (trace) {
        trace("Resize to " + $("commentCanvas").offsetWidth + "x" + $("commentCanvas").offsetHeight);
      }
      cm.setBounds();
      $("commentCanvas").style.border = "0px";
      $("c-region").style.display = "none";
      cm.setBounds();
    }
    isDownTB = false;
    isDownLR = false;
  });
};

function bindDebugger() {
  var output = $("debugger-output");

  function trace(msg) {
    if (typeof msg === "object") {
      var obj = {};
      for (var field in msg) {
        if (typeof msg[field] !== "function") {
          obj[field] = msg[field].toString();
        } else {
          obj[field] = "[function Function]";
        }
      }
      msg = JSON.stringify(obj, undefined, 2);
    } else if (msg === undefined) {
      msg = "[undefined]";
    } else if (typeof msg !== "string") {
      msg = msg.toString();
    }
    var lines = msg.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/ /g, "&nbsp;").split("\n");
    output.innerHTML = lines.join("<br>") + "<br>" + output.innerHTML;
  };
  window.trace = trace;
  $("debugger-input-area").addEventListener("keydown", function(e) {
    if (e.keyCode == 9) e.preventDefault()
  });
  $("debugger-input-area").addEventListener("keyup", function(e) {
    if (e.keyCode == 9) {
      e.preventDefault();
      this.innerHTML += "\t";
    }
  });
  $("debugger-run").addEventListener("click", function() {
    try {
      var cm = window.cm;
      eval($("debugger-input-area").innerText);
    } catch (e) {
      trace(e);
      console.log(e);
    }
  });
  for (var x in debugs) {
    $(x).addEventListener('click', function() {
      $("debugger-input-area").innerHTML = debugs[this.id];
    });
  }
};

function bindVideo(video, cm) {
  video.addEventListener("timeupdate", function() {
    if (cm.display === false) return;
    if (video.hasStalled) {
      cm.start();
      video.hasStalled = false;
    }
    cm.time(Math.floor(video.currentTime * 1000));
    displayTime(Math.floor(video.currentTime * 1000));
  });
  video.addEventListener("play", function() {
    cm.start();
  });
  video.addEventListener("pause", function() {
    cm.stop();
  });
  video.addEventListener("waiting", function() {
    cm.stop();
  });
  video.addEventListener("playing", function() {
    cm.start();
  });
};

function bindLiveTests(){
  $('test-live-1').addEventListener('click', function(){
    window.cm.start();
    var comment = {
      'text': "common danmaku",
      'mode': 1,
      'color': 0xffffff,
    };
    window.cm.send(comment);
  })
  $('test-live-2').addEventListener('click', function(){
    window.cm.start();
    var comment = {
      'text': "blue background danmaku",
      'mode': 1,
      'color': 0xffffff,
      'className': 'blue-background'
    };
    window.cm.send(comment);
  })
}

window.addEventListener("load", function() {
  bind();
  bindWindow();
  bindTests();
  bindLiveTests();
  bindResize();
  bindDebugger();
});
